#pragma once

#include "ccstd.hh"

namespace sirtet
{

class Node
{
  private:
    Node *parent = nullptr;
    std::queue<std::function<void(void)>> schedules;

  protected:
    std::vector<std::unique_ptr<Node>> children;

  public:
    std::string name;

  public:
    Node(const char *name);
    ~Node();

    virtual void update();
    virtual void after_update();

    template <typename T, typename... Args>
    std::unique_ptr<T> &make_child(Args &&...args);

    void add_child(std::unique_ptr<Node> &&child);
    std::size_t child_count();
    std::unique_ptr<Node> *find_child(const char *name);
    std::unique_ptr<Node> remove_child(const char *name);
    std::unique_ptr<Node> remove_child(std::function<bool(std::unique_ptr<Node> &)> predicate);

    bool has_parent();
    Node &get_parent();

    void add_schedule(std::function<void(void)> schedule);
};

template <typename T, typename... Args>
inline std::unique_ptr<T> &Node::make_child(Args &&...args)
{
    add_child(std::make_unique<T>(std::forward<Args>(args)...));
    return children[children.size() - 1];
}

} // namespace sirtet